package com.xlh.service.check.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.xlh.common.ResultEnum;
import com.xlh.dao.check.CheckMapperExt;
import com.xlh.dao.conclude.BusiFullMarkMapper;
import com.xlh.dao.conclude.ext.BusiFullMarkMapperExt;
import com.xlh.dao.conclude.helper.BusiFullMarkMapperHelper;
import com.xlh.dao.course.ext.ChapterMapperExt;
import com.xlh.dao.course.helper.ChapterMapperHelper;
import com.xlh.dao.courseTest.CourseQuestionRepositoryMapper;
import com.xlh.dao.user.helper.UserClassMapperHelper;
import com.xlh.dto.PageDTO;
import com.xlh.dto.conclude.BusiFullMarkDTO;
import com.xlh.dto.conclude.BusiFullMarkStudentScoreDTO;
import com.xlh.dto.course.ChapterOrderDTO;
import com.xlh.dto.course.CourseBasicDTO;
import com.xlh.dto.course.StatisticsDTO;
import com.xlh.dto.courseTest.AnswerSheetDTO;
import com.xlh.dto.courseTest.AnswerSheetTypeDTO;
import com.xlh.dto.courseTest.check.*;
import com.xlh.dto.courseTest.practice.PracticeClassDTO;
import com.xlh.dto.user.ClassCourseDTO;
import com.xlh.dto.user.UserInfoDTO;
import com.xlh.enums.LocalResourcesEnum;
import com.xlh.enums.PermissionEnum;
import com.xlh.enums.check.CheckStatusEnum;
import com.xlh.enums.check.CommentStatusEnum;
import com.xlh.enums.check.SubmitStatusEnum;
import com.xlh.enums.conclude.LikedSysFunkEnum;
import com.xlh.enums.course.ChapterEnum;
import com.xlh.enums.course.ChapterTypeEnum;
import com.xlh.enums.courseTest.CheckEnum;
import com.xlh.enums.user.ClassStatusEnum;
import com.xlh.exception.common.GlobalException;
import com.xlh.param.check.CheckClassParam;
import com.xlh.param.check.CheckSubmitParam;
import com.xlh.pojo.conclude.BusiFullMark;
import com.xlh.pojo.course.Chapter;
import com.xlh.pojo.course.ChapterBasic;
import com.xlh.pojo.courseTest.ExperimentReport;
import com.xlh.pojo.courseTest.Practice;
import com.xlh.pojo.system.Permission;
import com.xlh.pojo.user.Class;
import com.xlh.pojo.user.UserClass;
import com.xlh.properties.PandocProperties;
import com.xlh.service.check.CheckService;
import com.xlh.service.conclude.ConcludeBusiFullMarkService;
import com.xlh.service.conclude.ConcludeScoreService;
import com.xlh.service.course.ChapterService;
import com.xlh.service.course.CourseService;
import com.xlh.service.courseTest.*;
import com.xlh.service.system.SystemConfigService;
import com.xlh.service.user.ClassService;
import com.xlh.service.user.UserService;
import com.xlh.support.attendance.po.SettingMarkPO;
import com.xlh.util.BeanUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.xlh.enums.courseTest.CheckEnum.EXPERIMENT;
import static com.xlh.enums.courseTest.CheckEnum.PRACTICE;

/**
 * @author zhr 2019/4/3
 */
@Service
public class CheckServiceImpl implements CheckService {

    private static Logger logger = LoggerFactory.getLogger(CheckServiceImpl.class);

    @Autowired
    private PandocProperties pandocProperties;

    @Autowired
    private ChapterService chapterService;

    @Autowired
    private ChapterMapperExt chapterMapperExt;

    @Autowired
    private UserService userService;
    @Autowired
    private PracticeService practiceService;
    @Autowired
    private ExperimentService experimentService;
    @Autowired
    private ClassService classService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private UserClassService userClassService;

    @Autowired
    private CheckMapperExt checkMapperExt;

    @Autowired
    private SystemConfigService configService;

    @Autowired
    private ConcludeBusiFullMarkService concludeBusiFullMarkService;

    @Autowired
    private BusiFullMarkMapperExt busiFullMarkMapperExt;

    @Autowired
    private BusiFullMarkMapperHelper busiFullMarkMapperHelper;

    @Autowired
    private ConcludeScoreService concludeScoreService;

    @Autowired
    private ChapterMapperHelper chapterMapperHelper;

    @Autowired
    private UserClassMapperHelper userClassMapperHelper;

    @Autowired
    private QuestionRepositoryService questionRepositoryService;

    @Override
    public List<ClassDTO> listClass(List<Long> classIds, Integer type, Long courseId, Long userId) {
        CheckEnum checkEnum = CheckEnum.forType(type);

        // 查询课程下的章节
        List<ChapterBasic> chapterBasics = getChapterList(checkEnum, courseId);

        // 清洗chapter中的设置为隐藏资源的数据
        if (CollectionUtils.isEmpty(chapterBasics)) {
            return Lists.newArrayList();
        }
        // 查询班级列表
        List<Long> chapterIds = chapterBasics.stream().map(ChapterBasic::getId).collect(Collectors.toList());
        List<ClassDTO> resultList = checkMapperExt.selectClassChapterList(classIds, chapterIds, courseId, userId);

        // 查询随堂练习答案开关状态
        Map<Long, Permission> permissionMap = Maps.newHashMap();
        if (PRACTICE == checkEnum) {
            permissionMap = convertPermission(chapterIds, PermissionEnum.PRACTICE_ANSWER_CONTROL);
            // 过滤没有随堂练习习题
            List<Long> havePracticeChapterIds = questionRepositoryService.findHavePracticeChapterIds(chapterIds);
            resultList = resultList.stream().filter(classDTO -> havePracticeChapterIds.contains(classDTO.getChapterId())).collect(Collectors.toList());
        }

        // 实验课不处理
        List<ChapterCountDTO> classChapterList = getChapterIdClassIdCountMap(chapterIds, checkEnum);
        // 设置章节提交量
        Map<Long, Permission> finalPermissionMap = permissionMap;
        resultList.forEach(classDTO -> {
            if (PRACTICE == checkEnum) {
                classDTO.setSwitchOn(false);
                if (finalPermissionMap.containsKey(classDTO.getChapterId())) {
                    Integer status = finalPermissionMap.get(classDTO.getChapterId()).getStatus();
                    classDTO.setSwitchOn(Objects.equals(status , 1) ? true : false);
                }
            }

            for (ChapterBasic chapterBasic : chapterBasics) {
                if (chapterBasic.getName().equals(classDTO.getChapterName())) {
                    long countSubmit = classChapterList.stream()
                            .filter(chapterCountDTO -> Objects.equals(chapterCountDTO.getChapterId(), classDTO.getChapterId()))
                            .filter(chapterCountDTO -> Objects.equals(chapterCountDTO.getClassId(), classDTO.getId()))
                            .mapToLong(ChapterCountDTO::getCount).sum();
                    classDTO.setEndMessage(classDTO.getEnded() ? ClassStatusEnum.ENDED.getMessage() : ClassStatusEnum.UNFINISHED.getMessage());
                    classDTO.setCount(countSubmit);
                    if (classDTO.getTotal() == null) {
                        classDTO.setTotal(0L);
                    }
                }
            }
        });

        // 实验报告类型重排序返回结构
        if (EXPERIMENT == checkEnum) {
            List<Long> chapterSum = resultList.stream().map(ClassDTO::getChapterId).distinct().collect(Collectors.toList());
            List<ClassDTO> reorderResultList = Lists.newLinkedList();
            List<ChapterOrderDTO> chapterListOrder = chapterMapperExt.getOrderListByChaperId(chapterSum);

            Map<Long, List<ClassDTO>> mapByClassId = resultList.stream().collect(Collectors.groupingBy(ClassDTO::getId));
            Map<Long, List<ClassDTO>> mapByChapterId = resultList.stream().collect(Collectors.groupingBy(ClassDTO::getChapterId));

            Set<Long> longs = mapByClassId.keySet();
            for (Long classId : longs) {
                for (int i = 0; i < chapterListOrder.size(); i++) {
                    Long id = chapterListOrder.get(i).getId();
                    List<ClassDTO> classDTOS = mapByChapterId.get(id);
                    List<ClassDTO> filterResult = classDTOS.stream().filter(classDTO -> classDTO.getId().equals(classId)).collect(Collectors.toList());
                    reorderResultList.addAll(filterResult);
                }
            }
            resultList = reorderResultList;
        }
        resultList.forEach(ClassDTO::computeProportion);

        return resultList;
    }

    @Override
    public CheckDTO readDetails(Integer type, Long id, Long chapterId, Long classId, Long courseId) {
        CheckEnum checkEnum = CheckEnum.forType(type);
        List<UserClass> userIds = userClassService.getUserClassIds(classId, null);
        return checkEnum.readDetails(id, chapterId, userIds, courseId);
    }

    @Override
    public void updateJz(Long id, Boolean jz, Long quitId) {
        Practice practice = practiceService.selectByPrimaryKey(id);
        List<AnswerSheetTypeDTO> answerTypeList = JSONArray.parseArray(practice.getContent(), AnswerSheetTypeDTO.class);
        for (AnswerSheetTypeDTO answerSheetTypeDTO : answerTypeList) {
            if (answerSheetTypeDTO.getType() == 3) {
                for (AnswerSheetDTO answerSheetDTO : answerSheetTypeDTO.getAnswerSheetList()) {
                    if (quitId.toString().equals(answerSheetDTO.getId().toString())) {
                        answerSheetDTO.setRight(jz);
                    }
                }
            }
        }
        checkMapperExt.updateJz(id, JSONArray.toJSONString(answerTypeList));
    }

    @Override
    @Transactional
    public CheckDTO read(Long id, CheckSubmitParam param, Integer type) {

        // 1. 验证当前分数是否大于满分
        CheckEnum checkEnum = CheckEnum.forType(type);
        CheckDTO read = checkEnum.read(id, param);

        if(type == 1){ // 随堂练习
            Practice practice = practiceService.selectByPrimaryKey(id);
            Long chapterId = practice.getChapterId();
            String sysFunkKey = LikedSysFunkEnum.PRACTICE.getSysFunkKey();
            Chapter chapterInfo = chapterMapperHelper.getChapterByCondition(chapterId);
            Long courseId = chapterInfo.getCourseId();
            Long studentId = practice.getStudentId();
            // 查询学生班级ID
            UserClass userClass = userClassMapperHelper.getById(studentId);
            BusiFullMark busiFullMark = busiFullMarkMapperHelper.get(sysFunkKey, courseId, userClass.getClassId(), chapterId);

            if(param.getScore() > busiFullMark.getFullMark()){
                throw new GlobalException(ResultEnum.ERROR_FULL_MARK_THEN_SCORE);
            }

        }else if(type == 2){ // 实验报告

            ExperimentReport experimentReport = experimentService.selectByPrimaryKey(id);
            String sysFunkKey = LikedSysFunkEnum.REPORT.getSysFunkKey();
            Long chapterId = experimentReport.getChapterId();
            Chapter chapterInfo = chapterMapperHelper.getChapterByCondition(chapterId);
            Long courseId = chapterInfo.getCourseId();
            Long studentId = experimentReport.getStudentId();

            UserClass userClass = userClassMapperHelper.getById(studentId);
            BusiFullMark busiFullMark = busiFullMarkMapperHelper.get(sysFunkKey, courseId, userClass.getClassId(), chapterId);

            if(param.getScore() > busiFullMark.getFullMark()){
                throw new GlobalException(ResultEnum.ERROR_FULL_MARK_THEN_SCORE);
            }

        }else{

            throw new GlobalException(ResultEnum.BAD_REQUEST);
        }

        return read;
    }

    @Override
    public PageDTO<StudentListDTO> listStudent(
            Integer pageNum, Integer pageSize, Integer type, Long classId, Long chapterId, Integer status, String studentInfo, Long userId) {
        PageHelper.startPage(pageNum, pageSize);

        CheckEnum checkEnum = CheckEnum.forType(type);
        List<StudentListDTO> resultList = listStudentByType(classId, chapterId, status, studentInfo, userId, checkEnum);
        resultList.forEach(dto -> {

            // 提交状态展示 已批阅 未批阅 已提交 未提交
            if (dto.getCheck() != null) {
                dto.setSubmitMessage(dto.getCheck() ? CheckStatusEnum.YES.getMessage() : CheckStatusEnum.NO.getMessage());
            }else{
                dto.setSubmitMessage(SubmitStatusEnum.NO.getMessage());
            }
            // 设置评价状态
            if (StrUtil.isNotBlank(dto.getCheckResult())) {
                dto.setCheckMessage(CommentStatusEnum.YES.getMessage());
            }else{
                dto.setCheckMessage(CommentStatusEnum.NO.getMessage());
            }
        });

        PageInfo<StudentListDTO> pageInfo = new PageInfo<>(resultList);
        return new PageDTO<>(pageInfo);
    }

    private List<StudentListDTO> listStudentByType(Long classId, Long chapterId, Integer status, String studentInfo, Long userId, CheckEnum checkEnum) {
        switch (checkEnum) {
            case PRACTICE:
                return practiceService.listStudent(classId, chapterId, status, studentInfo, userId);
            case EXPERIMENT:
                return experimentService.listStudent(classId, chapterId, status, studentInfo, userId);
            default:
                return Lists.newArrayList();
        }
    }

    @Override
    public void archiveCheck(Long courseId, CheckClassParam param) {
        CheckEnum checkEnum = CheckEnum.forType(param.getType());

        // 查询课程下的章节
        List<ChapterBasic> chapterBasics = getChapterList(checkEnum, courseId);

        if (CollectionUtils.isEmpty(chapterBasics)) {
            throw new GlobalException("章节不存在");
        }

        // 查询指定条件(chapterIds, classId)的所有已批阅结果
        List<Long> chapterIds = chapterBasics.stream().map(ChapterBasic::getId).collect(Collectors.toList());
        List<String> pdfList;
        switch (checkEnum) {
            case PRACTICE:
                List<Practice> practiceList = practiceService.selectByChapterIdsClassId(chapterIds, param.getClassIdList().get(0));
                pdfList = practiceList.stream().map(Practice::getPdf).collect(Collectors.toList());
                if (!fileExist(pdfList, LocalResourcesEnum.PDF)) {
                    throw new GlobalException("当前无文件可归档,请批阅后再进行归档");
                }
                break;
            case EXPERIMENT:
                List<ExperimentReport> experimentReportList = experimentService.selectByChapterIdsClassId(chapterIds, param.getClassIdList().get(0));
                pdfList = experimentReportList.stream().map(ExperimentReport::getReportPdf).collect(Collectors.toList());
                List<String> wordList = experimentReportList.stream().map(ExperimentReport::getReportFile).collect(Collectors.toList());
                if (!fileExist(pdfList, LocalResourcesEnum.PDF) && !fileExist(wordList, LocalResourcesEnum.REPORT)) {
                    throw new GlobalException("当前无文件可归档,请批阅后再进行归档");
                }
                break;
            default:
                throw new GlobalException("请选择批阅类型");
        }
    }

    @Override
    public void archive(Long courseId, CheckClassParam param) {
        CheckEnum checkEnum = CheckEnum.forType(param.getType());

        // 查询课程下的章节
        List<ChapterBasic> chapterBasics = getChapterList(checkEnum, courseId);

        if (CollectionUtils.isEmpty(chapterBasics)) {
            throw new GlobalException("章节不存在");
        }

        Map<Long, ChapterBasic> chapterBasicMap = BeanUtil.mapByKey("id", chapterBasics);

        // 查询班级下所有的学生
        List<UserInfoDTO> studentList = userService.queryClassUser(param.getClassIdList(), null);
        Map<Long, UserInfoDTO> studentMap = BeanUtil.mapByKey("id", studentList);

        // 查询班级信息
        Class classInfo = classService.queryClass(param.getClassIdList().get(0));

        // 查询用户-班级映射
        List<UserClass> userClassList = userClassService.getUserClassIds(classInfo.getId(), null);
        Map<Long, Long> idUserIdMap = userClassList.stream().collect(Collectors.toMap(UserClass::getId, UserClass::getUserId));

        // 查询指定条件(chapterIds, classId)的所有已批阅结果
        List<Long> chapterIds = chapterBasics.stream().map(ChapterBasic::getId).collect(Collectors.toList());
        switch (checkEnum) {
            case PRACTICE:
                List<Practice> practiceList = practiceService.selectByChapterIdsClassId(chapterIds, param.getClassIdList().get(0));
                getFile(practiceList, chapterBasicMap, studentMap, classInfo, idUserIdMap, PRACTICE);
                break;
            case EXPERIMENT:
                List<ExperimentReport> experimentReportList = experimentService.selectByChapterIdsClassId(chapterIds, param.getClassIdList().get(0));
                getFile(experimentReportList, chapterBasicMap, studentMap, classInfo, idUserIdMap, EXPERIMENT);
                break;
            default:
                throw new GlobalException("请选择批阅类型");
        }
    }

    @Override
    public StatisticsDTO getClassCheckCount(Map<Long, List<ClassCourseDTO>> courseIdClassIdsMap, CheckEnum checkEnum) {
        // 重写接口实现
        if (courseIdClassIdsMap == null) {
            return new StatisticsDTO();
        }

        // 通过课程id获取一个较大的数据集合
        List<Long> courseIdList = Lists.newArrayList(courseIdClassIdsMap.keySet());
        List<ClassUncheckedCountDTO> list = listUncheckedByCourseIds(courseIdList, checkEnum);
        if (CollectionUtils.isEmpty(list)) {
            return new StatisticsDTO();
        }

        // 获取课程-班级-学生映射关系
        Map<Long, List<Long>> classIdStudentIdsMap = getClassIdStudentIdsMap(courseIdClassIdsMap.values());
        Map<Long, Map<Long, List<Long>>> courseClassStudentsMap = getCourseClassStudentsMap(courseIdClassIdsMap, classIdStudentIdsMap);
        list.forEach(dto -> {
            courseClassStudentsMap.forEach((courseId, classStudentMap) -> {
                if (Objects.equals(dto.getCourseId(), courseId)) {
                    classStudentMap.forEach((classId, students) -> {
                        if (students.contains(dto.getStudentId())) {
                            dto.setClassId(classId);
                        }
                    });
                }
            });
        });

        // 整合每个班级
        Map<Long, Long> classIdUncheckedCountMap = Maps.newHashMap();
        List<PracticeClassDTO> courseClassNameList = Lists.newArrayList();
        courseIdClassIdsMap.forEach((courseId, classes) -> {
            for (ClassCourseDTO clazz : classes) {
                long count = list.stream().filter(dto -> Objects.equals(dto.getCourseId(), courseId) && Objects.equals(dto.getClassId(), clazz.getId())).count();
                classIdUncheckedCountMap.merge(clazz.getId(), count, Long::sum);

                if (count != 0L) {
                    PracticeClassDTO dto = new PracticeClassDTO();
                    dto.setCourseId(courseId);
                    dto.setClassId(clazz.getId());
                    dto.setGrade(clazz.getGrade());
                    dto.setIs_ended(clazz.getEnded().toString());
                    courseClassNameList.add(dto);
                }
            }
        });

        convertToName(courseClassNameList);

        Long total = classIdUncheckedCountMap.values().stream().mapToLong(Long::longValue).sum();

        return new StatisticsDTO(total, null, courseClassNameList);
    }

    @Override
    public void deletePractice(Long id) {
        checkMapperExt.deletePractice(id);
    }

    /**
     * 满分项设置
     * @param classId 班级ID
     * @param courseId 课程ID
     * @param chapterId 章节ID
     * @param score
     * @param type
     */
    @Override
    public void settingFullMark(Long classId, Long courseId, Long chapterId, Integer type, Integer score ) {


        // 1. 判断业务类型
        CheckEnum checkEnum = CheckEnum.forType(type);
        if(ObjectUtil.isNull(checkEnum)){
            throw new GlobalException(ResultEnum.BAD_REQUEST);
        }
        String sysFunkKey = null;
        List<BusiFullMarkStudentScoreDTO> busiFullMarkStudentScoreDTOs = Lists.newArrayList();
        // 2. 随堂练习
        if(type == 1){
            sysFunkKey = LikedSysFunkEnum.PRACTICE.getSysFunkKey();
            // 获取当前本机的所有学生ID
            Integer maxScore = busiFullMarkMapperExt.findPracticeMaxScore(chapterId, classId);
            if(ObjectUtil.isNotNull(maxScore) && maxScore.compareTo(score) == 1){
                throw new GlobalException(ResultEnum.ERROR_FULL_MARK_CANTLESS_SCORE);
            }
            // 调用随堂练习查询方法
            busiFullMarkStudentScoreDTOs = busiFullMarkMapperExt.findCoursePracticeAvgScore(courseId, sysFunkKey, classId, null);
        }
        // 3. 实验
        if(type == 2){
            sysFunkKey = LikedSysFunkEnum.REPORT.getSysFunkKey();
            // 获取当前章节下的最大分值
            Integer maxScore = busiFullMarkMapperExt.findExperimentMaxScore(chapterId, classId);
            // 调用实验查询方法
            if(ObjectUtil.isNotNull(maxScore) && maxScore.compareTo(score) == 1){
                throw new GlobalException(ResultEnum.ERROR_FULL_MARK_CANTLESS_SCORE);
            }
            busiFullMarkStudentScoreDTOs = busiFullMarkMapperExt.findCourseExperimentAvgScore(courseId, sysFunkKey, classId, null);
        }

        // 存入到满分表
        SettingMarkPO settingMarkPO = new SettingMarkPO();
        settingMarkPO.setClassIdList(Lists.newArrayList(classId));
        settingMarkPO.setCourseId(courseId);
        settingMarkPO.setChapterId(chapterId);
        settingMarkPO.setFullMark(score);
        settingMarkPO.setBusiType(sysFunkKey);
        // 4. 设置分数
        concludeBusiFullMarkService.settingFullMark(settingMarkPO, null);

        // 更新工程认证表
        for (BusiFullMarkStudentScoreDTO busiFullMarkStudentScoreDTO : busiFullMarkStudentScoreDTOs) {

            Long studentId = busiFullMarkStudentScoreDTO.getStudentId();
            Double scoreDTOScore = busiFullMarkStudentScoreDTO.getScore();
            Integer fullMark = busiFullMarkStudentScoreDTO.getFullMark();
            concludeScoreService.updateScoreFromSys(courseId, studentId, sysFunkKey,
                    new BigDecimal(scoreDTOScore), new BigDecimal(fullMark));
        }

    }

    @Override
    public Integer getFullMark(Long classId, Long courseId, Long chapterId, Integer type) {

        String sysFunkKey = null;

        if(type == 1){
            sysFunkKey = LikedSysFunkEnum.PRACTICE.getSysFunkKey();
        }else if(type == 2){
            sysFunkKey = LikedSysFunkEnum.REPORT.getSysFunkKey();

        }else{
            throw new GlobalException(ResultEnum.BAD_REQUEST);
        }

        BusiFullMark busiFullMark = busiFullMarkMapperHelper.get(sysFunkKey, courseId, classId, chapterId);

        return busiFullMark.getFullMark();
    }


    @Override
    public void deleteReport(Long id) {

        // 删除原有的文件记录
        


        // 删除现有的数据库记录


    }


    private List<ClassUncheckedCountDTO> listUncheckedByCourseIds(List<Long> courseIdList, CheckEnum checkEnum) {
        switch (checkEnum) {
            case PRACTICE:
                return practiceService.selectUncheckedByCourseIds(courseIdList);
            case EXPERIMENT:
                return experimentService.selectUncheckedByCourseIds(courseIdList);
            default:
                return Lists.newArrayList();
        }
    }

    /**
     * 读取列表并将文件归类
     *
     * @param list
     * @param chapterBasicMap
     * @param studentMap
     * @param classInfo
     * @param idUserIdMap
     * @param checkEnum
     */
    private void getFile(List<? extends CheckRootDTO> list, Map<Long, ChapterBasic> chapterBasicMap, Map<Long, UserInfoDTO> studentMap, Class classInfo, Map<Long, Long> idUserIdMap, CheckEnum checkEnum) {
        // 临时文件目录,归档操作完成后要删除该目录
        String tempPath = pandocProperties.getTemp();

        // 迭代对文件归类
        for (CheckRootDTO dto : list) {
            // pdf文件是否存在
            if ((dto.getPdf() == null && dto.getReportPdf() == null) && (dto.getReportFile() == null)) {
                continue;
            }

            dto.setStudentId(idUserIdMap.get(dto.getStudentId()));

            // 获取pdf文件名称
            String pdf = dto.getPdf() != null ? dto.getPdf() : dto.getReportPdf();
            // 获取word文件名称
            String word = dto.getReportFile();

            // 学生重命名文件名称
            UserInfoDTO userInfo = studentMap.get(dto.getStudentId());
            String studentFileName = userInfo.getUserNumber() + "_" + userInfo.getName() + ".pdf";
            // 章节名称
            ChapterBasic chapter = chapterBasicMap.get(dto.getChapterId());
            String chapterName = chapter.getName();

            // 拷贝并重命名pdf文件
            copyFile(LocalResourcesEnum.PDF, pdf, studentFileName, chapterName);
            // 拷贝并重命名word文件
            copyFile(LocalResourcesEnum.REPORT, word, dto.getReportFileName(), chapterName);
        }

        // 创建zip文件
        String downloadName = classInfo.getName() + "_" + checkEnum.getMessage() + ".zip";
        File zipFile = ZipUtil.zip(tempPath);

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

        try (
                InputStream inputStream = new FileInputStream(zipFile);
                OutputStream outputStream = response.getOutputStream()
        ) {
            response.setContentType("application/x-download");
            response.addHeader("Content-Disposition", "attachment;filename=" + downloadName + ";filename*=UTF-8''" + URLUtil.encode(downloadName.trim()));
            IoUtil.copy(inputStream, outputStream);
            outputStream.flush();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new GlobalException("归档打包异常");
        } finally {
            FileUtil.del(zipFile);
            FileUtil.del(tempPath);
        }
    }

    /**
     * @param localResourcesEnum
     * @param file
     * @param fileRename
     * @param chapterName
     */
    private void copyFile(LocalResourcesEnum localResourcesEnum, String file, String fileRename, String chapterName) {
        if (file == null) {
            return;
        }

        // 临时文件目录,归档操作完成后要删除该目录
        String tempPath = pandocProperties.getTemp();
        // 临时文件目录完整路径
        String fullPathTemp = tempPath + "%s/%s";

        // 创建新的空文件
        File newFile = new File(String.format(fullPathTemp, chapterName, fileRename));
        FileUtil.touch(newFile);

        // 拷贝文件并重命名,
        File originFile = new File(localResourcesEnum.getLocalUploadPath(file));
        if (originFile.exists()) {
            try (BufferedInputStream in = FileUtil.getInputStream(originFile);
                 BufferedOutputStream out = FileUtil.getOutputStream(newFile);) {
                IoUtil.copy(in, out);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        } else {
            newFile.delete();
        }
    }

    private boolean fileExist(List<String> pdfList, LocalResourcesEnum localResourcesEnum) {
        if (CollectionUtils.isEmpty(pdfList)) {
            return false;
        }

        boolean result = false;
        for (String pdfFile : pdfList) {
            File file = new File(localResourcesEnum.getLocalUploadPath(pdfFile));
            result = result || file.exists();
        }

        return result;
    }

    private List<ChapterBasic> getChapterList(CheckEnum checkEnum, Long courseId) {
        // 查询课程下的章节
        List<Integer> types;

        List<ChapterBasic> result;

        switch (checkEnum) {
            case PRACTICE:
                types = ChapterTypeEnum.getTheoryTypes();
                result = chapterService.getChapterBasic(courseId, null, types, ChapterEnum.CHAPTER);
                break;
            case EXPERIMENT:
                types = ChapterTypeEnum.getExperimentTypes();
                result = chapterService.getChapterBasic(courseId, null, types, ChapterEnum.TASK);
                break;
            default:
                result = Lists.newArrayList();
                break;
        }

        return result.stream().filter(chapterBasic -> chapterBasic.getFalg() == 0).collect(Collectors.toList());
    }

    /**
     * @param chapterIds 章节id集合
     * @param checkEnum  批阅类型
     * @return 根据班级id-章节id-批阅数
     */
    private List<ChapterCountDTO> getChapterIdClassIdCountMap(List<Long> chapterIds, CheckEnum checkEnum) {
        switch (checkEnum) {
            case PRACTICE:
                return practiceService.countGroupByChapterIdClassId(chapterIds);
            case EXPERIMENT:
                return experimentService.countGroupByChapterIdClassId(chapterIds);
            default:
                return Lists.newArrayList();
        }
    }

    private Map<Long, Map<Long, List<Long>>> getCourseClassStudentsMap(Map<Long, List<ClassCourseDTO>> courseIdClassIdsMap, Map<Long, List<Long>> classIdStudentIdsMap) {
        Map<Long, Map<Long, List<Long>>> result = Maps.newHashMap();
        courseIdClassIdsMap.forEach((courseId, classes) -> {
            Map<Long, List<Long>> classIdStudentsInCourseMap = Maps.newHashMap();
            for (ClassCourseDTO clazz : classes) {
                if (classIdStudentIdsMap.get(clazz.getId()) != null) {
                    classIdStudentsInCourseMap.put(clazz.getId(), classIdStudentIdsMap.get(clazz.getId()));
                }
            }
            result.put(courseId, classIdStudentsInCourseMap);
        });
        return result;
    }

    private void convertToName(List<PracticeClassDTO> list) {
        List<CourseBasicDTO> courseList = courseService.listCourse(list.stream().map(PracticeClassDTO::getCourseId).collect(Collectors.toList()), null, null, null, null, null);
        Map<Long, CourseBasicDTO> courseMap = BeanUtil.mapByKey("id", courseList);
        List<Class> classList = classService.listClass(list.stream().map(PracticeClassDTO::getClassId).collect(Collectors.toList()), false);
        Map<Long, Class> classMap = BeanUtil.mapByKey("id", classList);

        list.forEach(dto -> {
            dto.setName(courseMap.get(dto.getCourseId()).getName());
            dto.setClassName(classMap.get(dto.getClassId()).getName());
        });
    }

    private Map<Long, List<Long>> getClassIdStudentIdsMap(Collection<List<ClassCourseDTO>> classList) {
        Set<ClassCourseDTO> classSet = Sets.newHashSet();
        for (List<ClassCourseDTO> classes : classList) {
            classSet.addAll(classes);
        }

        List<UserInfoDTO> studentList = userService.queryClassUser(Lists.newArrayList(classSet.stream().map(ClassCourseDTO::getId).collect(Collectors.toList())), null);
        Map<Long, List<UserInfoDTO>> classIdUserListMap = BeanUtil.aggByKeyToList("classId", studentList);

        Map<Long, List<Long>> result = Maps.newHashMap();
        classIdUserListMap.forEach((classId, userList) -> {
            List<Long> userIdList = userList.stream().map(UserInfoDTO::getId).collect(Collectors.toList());
            result.put(classId, userIdList);
        });
        return result;
    }

    private Map<Long, Permission> convertPermission(List<Long> objIds, PermissionEnum permissionEnum) {
        List<Permission> permissions = configService.queryPermission(objIds, permissionEnum);
        return BeanUtil.mapByKey("objId", permissions);
    }

}
